const db = require('../utils/db.js');
const { cryptMsg } = require('../utils/index');
const sessionDb = require('../utils/sessionDb');

async function getSessionByUid(uid) {
  // const sessionDb = new SessionDb();

  const userSessionKey = `user.${uid}`;
  const userSessList = sessionDb.get(userSessionKey).value() || [];

  if (!userSessList.length) return null;

  let user;

  userSessList.forEach(key => {
    const sessionKey = `session.${key}`;

    const sess = sessionDb.get(sessionKey)?.value();
    // eslint-disable-next-line no-underscore-dangle
    if (sess && sess._expire) {
      user = sess.user;
    } else {
      userSessList.delete(key);
      sessionDb.unset(sessionKey).write();
    }
  });

  sessionDb.set(userSessionKey, userSessList).write();

  return user;
}

/**
 * 生成ticket
 * @param {string} uid user uid
 * @param {string} prefix ticket prefix
 * @returns
 */
function genUserTicket(uid, prefix = 'signin') {
  const ts = Date.now() + 5 * 60 * 1000;
  const key = `${uid}:${ts}`;
  const salt = ts.toString().split('').reverse().toString();
  const { hash } = cryptMsg(key, salt);
  return `${prefix}:${uid}:${ts}:${hash}`;
}

async function validateTicketUser(ticket = '') {
  if (typeof ticket !== 'string') return false;
  const arr = ticket.split(':');
  if (!Array.isArray(arr) || arr.length !== 4) return false;

  const prefix = arr[0];
  const uid = arr[1];
  const ts = parseInt(arr[2], 10);
  const targetTicket = arr[3];
  const key = `${uid}:${ts}`;
  const salt = ts.toString().split('').reverse().toString();

  if (ts < Date.now()) return false;

  const { hash } = cryptMsg(key, salt);

  if (hash !== targetTicket) return false;

  let user;
  if (prefix === 'signin') {
    user = await getSessionByUid(uid);
  } else if (prefix === 'signout') {
    user = await getUserByUid(uid);
  }

  return user;
}

function getSafeUserInfo(user = {}) {
  const { password, salt, ...restUser } = user;
  return restUser;
}

async function getUserByName(name = '', safe = true) {
  const user = db.get('users').find({ name }).value();

  if (safe && user) {
    return getSafeUserInfo(user);
  }

  return user;
}

async function getUserByUid(uid, safe = true) {
  const user = db.get('users').find({ id: uid }).value();

  if (safe && user) {
    return getSafeUserInfo(user);
  }

  return user;
}

async function validateUserPwd(name, password) {
  if (!name || !password) return false;
  const user = await getUserByName(name, false);

  if (!user) return false;

  const { hash } = cryptMsg(password, user.salt);
  if (hash !== user.password) return false;

  return getSafeUserInfo(user);
}

module.exports = {
  genUserTicket,
  validateTicketUser,
  getUserByName,
  getUserByUid,
  validateUserPwd,
};
